// const NodeEnvSetter = require('../NodeEnvSetter')

class EnvMark {
  startKey;
  endKey;

  options = {
    getEnvironmentFunctionName: '__getEnvironmentFunction__',
    splitStr: '☺'
  };
  // nodeEnvSetter = new NodeEnvSetter();

  constructor(options) {
    Object.assign(this.options, options)
    this.startKey = this.options.getEnvironmentFunctionName + 'start(';
    this.endKey = ")" + this.options.getEnvironmentFunctionName + 'end';
    if (this.init()) {
      this.mark();
    }

  }


  // apply(compiler){
  //   compiler.hooks.compilation.tap(EnvMark.name, (compilation, compilationParams) => {
  //     compilation.hooks.buildModule.tap(EnvMark.name, (module) => {
  //       module.useSourceMap = true;
  //     });
  //   })
  // }

  apply(compiler) {
    // this.nodeEnvSetter.apply(compiler);
    if (!this.init()){
      return;
    }
    let self = this;
    let options = self.options;
    
    if (!compiler.hooks.environment) {
      return
    }
    // 在加载环境变量完成后修改变量值
    compiler.hooks.environment.tap(EnvMark.name, () => {
      self.mark();
    });

    // 创建normalModuleFactory时执行
    compiler.hooks.normalModuleFactory.tap(EnvMark.name, (normalModuleFactory) => {
      // 加载依赖时，修改变量为原来的值
      normalModuleFactory.hooks.resolve.tapAsync(EnvMark.name, (resolveData, callback) => {
        if (resolveData.request && resolveData.request.includes(options.getEnvironmentFunctionName)) {
          // 提取变量
          resolveData.request = self.replaceEnv(resolveData.request, function (env) {
            return { text: env.val };
          });
          if (resolveData.userRequest) {
            resolveData.userRequest = self.replaceEnv(resolveData.userRequest, function (env) {
              return { text: env.val };
            });
          }
        }
        callback();
      });
    });

    // 编译完成之后替换 __getEnvironmentFunction__ 为方法
    compiler.hooks.afterCompile.tap(EnvMark.name, compilation => {

      for (const name in compilation.assets) {
        let isReplace = false;
        let content;
        if (name.endsWith('.js')){
          let assets = compilation.assets[name];
          content = self.replaceEnv(assets.source(), function (env, text, startIndex, endIndex) {
            isReplace = true;
            // 检查替换前面字符是什么
            let start = '';
            // 记录从哪个下标替换
            let si = startIndex;
            // 如果前一个字符是双引号
            if (text[startIndex - 1] == '"' || text[startIndex - 1] == "'") {
              // 如果双引号前一个字符是转译\（当前字符串是xxxx\"）
              if (text[startIndex - 2] == '\\') {
                start = '"+'; // 生成字符串为：xxxx\"+REPLACT()
              } else { // 如果不是转译，则开始下标-1，截取掉前面的双引号
                si--;
              }
            } else { // 如果前面是非双引号的字符，直接添加字符串拼接
              start = '"+';
            }

            let end = '';
            let ei = endIndex;
            // 如果后面字符不是双引号
            if (text[endIndex] != '"' && text[endIndex] != "'") {
              end = '+"'; // 添加字符串拼接，REPLACT()+"\"xx"
            } else {
              ei++;
            }

            return {
              text: `${start}${options.getEnvironmentFunctionName}('${env.key}', '${env.val}')${end}`,
              start: si,
              end: ei
            };
          });

          if (isReplace) {
            let __fn = `var ${options.getEnvironmentFunctionName} = function(key, value){return value;};`;
            content = __fn + content;
          }

        } else if (name.endsWith('.html')){
          let assets = compilation.assets[name];
          content = self.replaceEnv(assets.source(), function (env) {
            isReplace = true;
            return { text: env.val };
          });
        } else {
          continue
        }

        if (!isReplace) {
          continue
        }

        Object.assign(compilation.assets[name], {
          text: content,
          buffer: undefined, // 写出文件的时候，node_modules\webpack\lib\Compiler.js[693] 会调用当前对象的 buffer 或 source方法，自定buffer为undefined，强制调用source方法
          source: function () {
            return this.text;
          }
        })
      }
    })
  }

  parseEnvValue(env) {
    let self = this;
    let items = env.split(this.options.splitStr);
    let key = items[0].substring(self.startKey.length);
    let val = items[1].substring(0, items[1].length - self.endKey.length);
    return { key, val }
  }
  replaceEnv(content, replace) {
    let self = this;
    let start = 0;
    let end = 0;
    while ((start = content.indexOf(self.startKey)) != -1) {
      end = content.indexOf(self.endKey, start) + self.endKey.length;

      let item = content.substring(start, end);
      let parse = self.parseEnvValue(item);

      let rep = replace(parse, content, start, end);
      rep.start = rep.start || start;
      rep.end = rep.end || end;

      let before = content.substring(0, rep.start);
      let after = content.substring(rep.end);

      content = before + rep.text + after;
    }
    return content;
  }

  mark(){
    let self = this;
    let options = self.options;
    let env = process.env;
    for (let key in env) {
      let val = env[key];
      if (key.startsWith('VUE_APP_') && !val.startsWith(self.startKey)) {
        let fnstr = `${self.startKey}${key}${options.splitStr}${val}${self.endKey}`;
        env[key] = fnstr
      }
    }
  }
  init(){
    if (process.env.NODE_ENV == 'development') {
      console.log("development 环境不启用，如果需要启用请运行build命令或在.env.xxx文件中指定 NODE_ENV 和 BABEL_ENV 为 production");
      return false;
    }
    console.log('EnvMark 启用')
    return true;
  }
}

module.exports = EnvMark;